package utils

import (
	"fmt"
	"gitee.com/ymofen/gobase/factory"
	"sort"
	"strings"
)

var (
// inner_factory_var SyncMap
)

type KvPair struct {
	Key string
	Val interface{}
}

func VarToStr(v interface{}) string {
	s := GetStrValue(v, "")
	if len(s) == 0 {
		return fmt.Sprintf("%p", v)
	}
	return s
}

type TFactoryVarFunc = func(sender interface{}, args ...interface{}) interface{}

func RegisterFactoryVarFunc(id interface{}, cb func(sender interface{}, args ...interface{}) interface{}) {
	factory.RegisterVar(VarToStr(id), cb)
	//inner_factory_var.Store(id, cb)
}

func RegisterFactoryVar(id interface{}, v interface{}) {
	factory.RegisterVar(VarToStr(id), v)
	//inner_factory_var.Store(id, v)
}

func UnRegisterFactoryVar(id interface{}) {
	factory.RemoveVar(VarToStr(id))
	//inner_factory_var.Remove(id)
}

func GetFactoryVar(id interface{}) interface{} {
	//v, _ := inner_factory_var.Load(id)
	v := factory.GetVar(VarToStr(id))
	return v
}

func RangeFactoryVarsFuncEx(sortflag int, filter func(key string, value interface{}) bool,
	less_sortfunc func(k0 string, v0 interface{}, k1 string, v1 interface{}) bool,
	rangfn func(key string, val interface{}) bool) {

	rval := make([]KvPair, 0, 1024)
	var appendfn = func(key string, value interface{}) {
		var itm KvPair
		itm.Key = key
		itm.Val = value
		rval = append(rval, itm)
	}

	factory.RangeVarListEx(func(key string, value interface{}) bool {
		keystr := key
		if fn, ok := value.(TFactoryVarFunc); ok {
			val := fn(nil)
			if filter(keystr, val) {
				appendfn(keystr, val)
			}
		} else {
			if filter(keystr, value) {
				appendfn(keystr, value)
			}
		}
		return true
	})

	if sortflag == 1 && less_sortfunc != nil {
		sort.Slice(rval, func(i, j int) bool {
			return less_sortfunc(rval[i].Key, rval[i].Val, rval[j].Key, rval[j].Val)
		})
	}

	for i := 0; i < len(rval); i++ {
		if !rangfn(rval[i].Key, rval[i].Val) {
			return
		}
	}
}

//
//func RangeFactoryVarsFunc(rangefn func(key string, val interface{}) bool) {
//	inner_factory_var.Range(func(key, value interface{}) bool {
//		keystr, _ := key.(string)
//		if fn, ok := value.(TFactoryVarFunc); ok {
//			val := fn(nil)
//			return rangefn(keystr, val)
//		} else {
//			return rangefn(keystr, value)
//		}
//	})
//}
//
///*
//**
//
//	如果找不到替换成默认值
//*/
//func ReplacePlaceholderDef(s string, start, end string, def string) string {
//	for {
//		id := GetBetween(s, start, end, 0)
//		if len(id) == 0 {
//			break
//		}
//
//		replkey := fmt.Sprintf("%s%s%s", start, id, end)
//		if ok, v := InvokeFactoryVarFunc(id, nil); ok {
//			s = strings.ReplaceAll(s, replkey, GetStrValue(v, ""))
//		} else {
//			s = strings.ReplaceAll(s, replkey, def)
//		}
//	}
//	return s
//}

/*
**

	如果找不到, 不替换
*/
func ReplacePlaceholderFunc(s string, start, end string, getParamFunc func(key string) (ok bool, v interface{})) string {
	idx := 0
	for {
		id := GetBetween(s, start, end, idx)
		if len(id) == 0 {
			break
		}

		if ok, v := getParamFunc(id); ok {
			replkey := fmt.Sprintf("%s%s%s", start, id, end)
			s = strings.ReplaceAll(s, replkey, GetStrValue(v, ""))
		} else {
			idx++
		}
	}
	return s
}

/*
如果找不到, 不替换
*/
func ReplacePlaceholderJSONEscape(s string, start, end string) string {
	idx := 0
	for {
		id := GetBetween(s, start, end, idx)
		if len(id) == 0 {
			break
		}

		if ok, v := InvokeFactoryVarFunc(id, nil); ok {
			replkey := fmt.Sprintf("%s%s%s", start, id, end)
			strv := GetStrValue(v, "")
			strv = EscapeJsonStrSimple(strv)
			s = strings.ReplaceAll(s, replkey, strv)
		} else {
			idx++
		}
	}
	return s
}

/*
如果找不到, 不替换
*/
func ReplacePlaceholder(s string, start, end string) string {
	idx := 0
	for {
		id := GetBetween(s, start, end, idx)
		if len(id) == 0 {
			break
		}

		if ok, v := InvokeFactoryVarFunc(id, nil); ok {
			replkey := fmt.Sprintf("%s%s%s", start, id, end)
			s = strings.ReplaceAll(s, replkey, GetStrValue(v, ""))
		} else {
			idx++
		}
	}
	return s
}

func InvokeFactoryVarFunc(id interface{}, sender interface{}, args ...interface{}) (bool, interface{}) {
	obj := factory.GetVar(VarToStr(id))
	if obj != nil {
		if fn, ok := obj.(TFactoryVarFunc); ok {
			return true, fn(sender, args...)
		} else {
			return true, obj
		}
	}
	return false, nil
}

func TryInvokeFactoryVarFunc(id interface{}, def interface{}, sender interface{}, args ...interface{}) interface{} {
	if ok, ret := InvokeFactoryVarFunc(id, sender, args...); ok {
		return ret
	} else {
		return def
	}
}
